package com.whfc.iot.mach.event;

import com.google.common.cache.LoadingCache;
import com.whfc.common.generator.KeyGeneratorUtil;
import com.whfc.common.util.JSONUtil;
import com.whfc.hdc.dto.DeviceUpgradeDTO;
import com.whfc.hdc.dto.DeviceUpgradeDataDTO;
import com.whfc.iot.mach.constant.MsgConst;
import com.whfc.iot.mach.entity.MachMsg0x82;
import com.whfc.iot.mach.entity.UpgradeCacheKey;
import com.whfc.iot.mach.redis.MachUpgradeLockDao;
import com.whfc.iot.mach.service.DeviceUpgradeService;
import com.whfc.iot.session.Session;
import com.whfc.iot.session.SessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 设备上线事件后 - 判断设备是否需要升级
 * @author: xugcheng
 * @version: 1.0
 * @date: 2019/8/23 14:49
 */
@Component
public class DeviceOnlineEventUpgradeJudgeListener implements ApplicationListener<DeviceOnlineEvent> {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private DeviceUpgradeService deviceUpgradeService;

    @Resource(name = "deviceUpgradeCache")
    private LoadingCache<UpgradeCacheKey, DeviceUpgradeDTO> deviceUpgradeCache;

    @Autowired
    private SessionManager sessionManager;

    @Autowired
    private MachUpgradeLockDao lockDao;

    @Override
    @Async
    public void onApplicationEvent(DeviceOnlineEvent event) {
        try {
            Integer deviceId = event.getDeviceId();
            Integer deviceType = event.getDeviceType();
            Integer seq = event.getSeq();
            String masterVer = event.getMasterVer();
            String slaveVer = event.getSlaveVer();

            //查询升级策略
            DeviceUpgradeDTO upgradeDTO = deviceUpgradeCache.get(new UpgradeCacheKey(deviceType, deviceId, masterVer, slaveVer));
            logger.debug("硬件是否需要升级,{}", JSONUtil.toString(upgradeDTO));
            if (upgradeDTO != null && upgradeDTO.getNeedUpgrade()) {

                //升级前,先加乐观锁
                long lockValue = KeyGeneratorUtil.genLongId();
                lockDao.lock(deviceId, lockValue);

                logger.info("硬件升级,deviceId:{},masterOrslave:{},oldVer:{},newVer:{},lockValue:{}", deviceId, upgradeDTO.getMasterOrSlave(), upgradeDTO.getOldVer(), upgradeDTO.getNewVer(), lockValue);
                DeviceUpgradeDataDTO upgradeDataDTO = deviceUpgradeService.getDeviceUpgradeData(deviceType, upgradeDTO.getMasterOrSlave(), upgradeDTO.getNewVer());
                if (upgradeDataDTO != null) {
                    //构造0x82
                    MachMsg0x82 resMsg = new MachMsg0x82();
                    resMsg.setStartFlag(MsgConst.START_FLAG);
                    resMsg.setDeviceType(deviceType);
                    resMsg.setDeviceId(deviceId);
                    resMsg.setSeq(seq + 1);
                    resMsg.setCmd(MsgConst.DOWNSTREAM_CMD_0x82);

                    resMsg.setMasterOrSlave(upgradeDTO.getMasterOrSlave());
                    resMsg.setVer(upgradeDTO.getNewVer());
                    resMsg.setSubPackageTotal(upgradeDataDTO.getSubPackageTotal());
                    resMsg.setSubPackageSeq(upgradeDataDTO.getSubPackageSeq());
                    resMsg.setSubPackageData(upgradeDataDTO.getSubPackageData());

                    //延迟发出数据
                    TimeUnit.SECONDS.sleep(2);

                    //获取当前加锁值
                    long curLockValue = lockDao.getLock(deviceId);
                    logger.info("judge-lock,deviceId:{},lockValue:{},curLockValue:{}", deviceId, lockValue, curLockValue);
                    if (curLockValue == lockValue) {
                        //响应0x82
                        Session session = sessionManager.getSessionByDeviceId(deviceId);
                        session.getChannel().writeAndFlush(resMsg).addListener(future -> {
                            lockDao.unlock(deviceId);
                            logger.info("0x82发送结果,deviceId={},isDone={},isSuccess={}", deviceId, future.isDone(), future.isSuccess());
                        });
                    }
                }

            }

        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
        }

    }
}
